Skip to content

Conversation

@rengolin
Copy link
Member Author

rengolin commented Sep 4, 2025

@llvm/mlir-area-team

@llvmbot
Copy link
Member

llvmbot commented Sep 4, 2025

@llvm/pr-subscribers-mlir

Author: Renato Golin (rengolin)

Changes

As discussed in:


Full diff: https://github.com/llvm/llvm-project/pull/156859.diff

1 Files Affected:

  • (modified) mlir/docs/Rationale/RationaleLinalgDialect.md (+73-14)
diff --git a/mlir/docs/Rationale/RationaleLinalgDialect.md b/mlir/docs/Rationale/RationaleLinalgDialect.md
index 8975b0a7d515e..4426d3fb9b3c2 100644
--- a/mlir/docs/Rationale/RationaleLinalgDialect.md
+++ b/mlir/docs/Rationale/RationaleLinalgDialect.md
@@ -411,6 +411,20 @@ and is used as a lowering target for Linalg, enabling further transformations
 and combination of semantically-loaded and lower-level inputs. As such, Linalg
 is intended to complement Affine rather than replace it.
 
+### Summary of Existing Alternatives a Picture<a name="observationssummary"></a>
+Lastly, we summarize our observations of lessons from [Prior
+Art](#prior-art)---when viewed under the lense of our [Core Guiding
+Principles](#guiding_principles)---with the following picture.
+
+<img width="1200" alt="MLIR Codegen Flow"
+src="https://user-images.githubusercontent.com/10148468/73613904-2f720a00-45c8-11ea-8265-1c856c02525b.png">
+
+This figure is not meant to be perfectly accurate but a rough map of how we view
+the distribution of structural information in existing systems, from a
+codegen-friendly angle. Unsurprisingly, the
+[Linalg Dialect](../Dialects/Linalg/_index.md) and its future evolutions aspire
+to a position in the top-right of this map.
+
 ## Core Guiding Principles<a name="guiding_principles"></a>
 
 ### Transformations and Simplicity First<a name="transformations_first"></a>
@@ -506,6 +520,65 @@ potential by introducing lower-level IR ops and *smaller* Linalg ops.
 This gradually reduces the potential, all the way to Loops + VectorOps
 and LLVMIR.
 
+### Interchangeability of Forms<a name="forms"></a>
+
+Linalg's various forms (named, generic) also carry information, and that
+information should be preserved as much as possible during the progressive
+lowering. A `matmul` operation is a special case of a `contract` operation,
+which in turn is a special case of `generic` operation. Transformations on
+the more special forms should not be converted to the more generic ones
+unnecessarily, in the same way that they should not be broken down into
+loops + arithmetic if they can still be represented as a Linalg op.
+
+#### Generic, Category, Named<a name="generic_category_named"></a>
+
+The core Linalg operation tree has three forms:
+* **Generic:** Represented by `linalg.generic` and can encode all perfectly-nested
+loop operations.
+* **Category:** Represented by `linalg.contract` and `linalg.elementwise`,
+which are special (einsum) forms of the `generic` operation.
+* **Named:** All _named_ forms that can lower to either _category_ or
+_generic_ forms. For example, `linalg.matmul`, `linalg.add`, etc.
+
+Unlike lowering to loops, the different Linalg forms that are derived from
+`linalg.generic` are *equivalent*. It should always be possible to convert
+a named operation into a generic and back to named, if the semantics is
+preserved. The various forms in the Linalg dialect are meant to facilitate
+pattern matching (single operations or DAGs) and to be able to consider
+different forms as *canonical* for different transforms.
+
+#### Special Operations<a name="special_ops"></a>
+
+Not all Linalg operations represent perfectly nested loops, and therefore
+cannot be represented as a `linalg.generic`. There are two kinds of Linalg
+operations that fall into this category:
+* **Composite:** Operations that compose multiple Linalg operations, for
+example `linalg.softmax`. These can be converted to a DAG of Linalg operations
+(in any form).
+* **Special Named:** Operations that are usually matched against library calls
+or special lowering, but can only be lowered to a combination of Linalg and
+non-Linalg operations, for example `linalg.*conv*`, `linalg.winograd*`,
+`linalg.pooling*`, etc.
+
+#### Canonical Forms<a name="canonical_forms"></a>
+
+With multiple (often exchangeable) forms, and with transformation simplicity
+in mind, compilers should aim for reducing matching and replacing complexity
+as much as possible. When matching a single operation with a complex pattern,
+having all the information from a `generic` is useful to iteratively match
+different patterns in turn. However, when assembling a DAG of operations to
+form a pattern, it's much simpler to match against named operations (like
+`max` + `div` + `reduce` + `broadcast`) than their generic counterparts.
+
+This is where the interchangeability of forms comes in handy. Linalg has the
+ability to specialize and generalize in order to convert the IR to a form that
+is easier for a particular type of transform. With forms being semantically
+equivalent, one can convert back-and-forth throughout the various transforms
+to match the needs of each transform. For that particular transform, such
+form can be considered _canonical_ and therefore "expected" for the pattern
+to _match_. This reduces complexity of pattern matchers and simplifies compiler
+pipelines.
+
 ### Composable and Declarative Transformations<a name="declarative_transformations"></a>
 Complex and impactful transformations need not be hard to manipulate, write or
 maintain. Mixing XLA-style high-level op semantics knowledge with generic
@@ -606,17 +679,3 @@ Considering the *potential* described during the discussion on
 transformation would dictate that the potential remains constant.
 In contrast, Linalg advocates for ***monotonicity*** under
 transformations.
-
-### Summary of Existing Alternatives a Picture<a name="observationssummary"></a>
-Lastly, we summarize our observations of lessons from [Prior
-Art](#prior-art)---when viewed under the lense of our [Core Guiding
-Principles](#guiding_principles)---with the following picture.
-
-<img width="1200" alt="MLIR Codegen Flow"
-src="https://user-images.githubusercontent.com/10148468/73613904-2f720a00-45c8-11ea-8265-1c856c02525b.png">
-
-This figure is not meant to be perfectly accurate but a rough map of how we view
-the distribution of structural information in existing systems, from a
-codegen-friendly angle. Unsurprisingly, the
-[Linalg Dialect](../Dialects/Linalg/_index.md) and its future evolutions aspire
-to a position in the top-right of this map.

Copy link
Member

@kuhar kuhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The wording makes sense to me. I'm not an authority on linalg, so please wait for folks more invested in linalg to review as well.

Copy link
Contributor

@banach-space banach-space left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Posting more comments as I go through this.

information should be preserved as much as possible during the progressive
lowering. A `matmul` operation is a special case of a `contract` operation,
which in turn is a special case of `generic` operation. Transformations on
the more special forms should not be converted to the more generic ones
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this about the ops being converted or the transformations?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both?

The idea is that "ops being converted" help simplify "transformations". So additional conversions between transformations can help if they assume different canonical forms. But IF and only IF the forms are semantically equivalent, thus, linalg forms.

This is where the interchangeability of forms comes in handy. Linalg has the
ability to specialize and generalize in order to convert the IR to a form that
is easier for a particular type of transform. With forms being semantically
equivalent, one can convert back-and-forth throughout the various transforms
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this an actual conversion or matching on interface?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actual conversion. We have discussed interfaces last year (the forum links in this PR), but the agreement was to keep using forms for now and see if we can generalize to interfaces later. Having the forms may be a bit too verbose, but it will give us enough data on how to design the interfaces if we end up doing it.

Comment on lines +546 to +548
as much as possible. When matching a single operation with a complex pattern,
having all the information in a `generic` is useful to iteratively match
different patterns in turn. However, when assembling a DAG of operations to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, would I ever want to (or need to) match linalg.generic if matching a named (or a category) Op was an option? This implies that in some cases matching linalg.generic might be more desirable, but I've always struggle to find a good example.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you get a named op from the front-end, life is simple. But if you get a generic, you have to make choices.

You can:

  1. run a pass to convert to a named op (currently O(num_gen_attr x num_named_ops)) and then match against that.
  2. iteratively match each generic attribute to a precise form (O(num_gen_attr) only) and match directly.

The first approach is helpful if you have a lot of different forms and want to normalize to a canonical form that your passes expect. One-off cost at the beginning of the pipeline, no cost later on.

The second approach is much faster if only a single pass needs to look at that operation (or multiple passes, one for each operation in different forms), since you match one attribute at a time with a particular pattern (not a list of all patterns).

Makes sense?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants